package com.kandinfo.base.admin.repository.mongo;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;

public abstract class MongoRepository<T extends Object, ID extends Serializable> {

    MongoTemplate mongoTemplate;

    public void setMongoTemplate(MongoTemplate mongoTemplate) {
        this.mongoTemplate = mongoTemplate;
    }

    public abstract Class<? extends T> getTClass();

    /**
     * Create a {<span class="referer">@link</span> Tree} collection if the collection does not already exists
     */
    public void createCollection() {
        if (!mongoTemplate.collectionExists(getTClass())) {
            mongoTemplate.createCollection(getTClass());
        }
    }

    /**
     * Drops the {<span class="referer">@link</span> Tree} collection if the collection does already exists
     */
    public void dropCollection() {
        if (mongoTemplate.collectionExists(getTClass())) {
            mongoTemplate.dropCollection(getTClass());
        }
    }

    public Page<T> findAll(Pageable pageable) {
        return null;
    }

    public T save(T entity) {
        mongoTemplate.save(entity);
        return entity;
    }

    public T findOne(ID id) {
        return mongoTemplate.findById(id, getTClass());
    }

    public boolean exists(ID id) {
        return mongoTemplate.exists(Query.query(Criteria.where("id").is(id)), getTClass());
    }

    public long count() {
        return mongoTemplate.count(null, getTClass());
    }

    public void delete(ID id) {
        mongoTemplate.remove(findOne(id));
    }

    public void delete(T entity) {
        mongoTemplate.remove(entity);
    }

    public void delete(Iterable<? extends T> entities) {
        for (T t : entities) {
            mongoTemplate.remove(t);
        }
    }

    public void deleteAll() {
        mongoTemplate.remove(null, getTClass());
    }

    @SuppressWarnings("unchecked")
    public List<T> findByCondition(Criteria criteria) {
        return (List<T>) mongoTemplate.find(Query.query(criteria), getTClass());
    }

    @SuppressWarnings("unchecked")
    public List<T> findByQuery(Query query) {
        return (List<T>) mongoTemplate.find(query, getTClass());
    }

    public T findOne(Criteria criteria) {
        return mongoTemplate.findOne(Query.query(criteria), getTClass());
    }

    @SuppressWarnings("unchecked")
    public List<T> findAll(Criteria criteria) {
        return (List<T>) mongoTemplate.find(Query.query(criteria), getTClass());
    }

    @SuppressWarnings("unchecked")
    public Page<T> findAll(Criteria criteria, Pageable pageable) {
        long count = mongoTemplate.count(Query.query(criteria), getTClass());
        Page<T> page = new PageImpl<T>((List<T>) mongoTemplate.find(Query.query(criteria).with(pageable), getTClass()),
                pageable, count);
        return page;
    }

    @SuppressWarnings("unchecked")
    public List<T> findAll(Criteria criteria, Sort sort) {
        return (List<T>) mongoTemplate.find(Query.query(criteria).with(sort), getTClass());
    }

    @SuppressWarnings("unchecked")
    public List<T> findAll(Criteria criteria, Pageable pageable, Sort sort) {
        return (List<T>) mongoTemplate.find(Query.query(criteria).with(sort).with(sort), getTClass());
    }

    @SuppressWarnings("unchecked")
    public List<T> findAll(Query query) {
        return (List<T>) mongoTemplate.find(query, getTClass());
    }

    public long count(Criteria criteria) {
        return mongoTemplate.count(Query.query(criteria), getTClass());
    }

    @SuppressWarnings("unchecked")
    public List<T> findAll() {
        return (List<T>) mongoTemplate.findAll(getTClass());
    }

    public List<T> findAll(Sort sort) {
        Query query = new Query();
        query.with(sort);
        mongoTemplate.find(query, getTClass());
        return null;
    }

    @SuppressWarnings("unchecked")
    public List<T> findAll(Collection<ID> ids) {
        return (List<T>) mongoTemplate.find(Query.query(Criteria.where("id").in(ids)), getTClass());
    }

    public void insertAll(Collection<?> entities) {
        mongoTemplate.insertAll(entities);
    }

    public <S extends T> List<S> save(Iterable<S> entities) {
        List<S> list = new ArrayList<S>();
        for (S s : entities) {
            mongoTemplate.save(entities);
            list.add(s);
        }
        return list;
    }

    public void flush() {
    }

    public T saveAndFlush(T entity) {
        return save(entity);
    }

    public void deleteInBatch(Iterable<T> entities) {
        delete(entities);
    }

    public void deleteAllInBatch() {
        deleteAll();
    }

    public T getOne(ID id) {
        return mongoTemplate.findById(id, getTClass());
    }
}
